// Since this must be included before #include<windows.h>
#if defined(WIN32)
#   include <Winsock2.h>
#   include <Ws2tcpip.h>
#endif

#include "iConfig.hpp"

#if GLF_ENABLE_DEBUGGER

#if GLF_PLATFORM_WIN32
#    pragma comment(lib, "ws2_32.lib")
#    pragma comment(lib, "Dbghelp.lib")
#endif

#include <glf/app.h>
#include <glf/core/types.h>
#include <glf/core/timer.h>
#include <glf/core/thread.h>
#include <glf/core/mutex.h>
#include <glf/debugger/debugger.h>
#include <glf/debugger/netInterface.h>
#include <glf/debugger/memoryMonitor.h>
#include <glf/debugger/tweaker.h>
#include <glf/debugger/perfCounters.h>
#include <glf/debugger/macros.h>
#include <glf/debugger/console.h>
#include <glf/debugger/profiler.h>
#include <glf/debugger/fileSystem.h>
#include <glf/debugger/network.h>
#include <cctype>

#if defined(WIN32) && (GLF_PLATFORM_WP8 == 0)
#	include <Winreg.h>
#	include <imagehlp.h>
#endif

#if GLF_GRAPHICAL_API_OPENGL
#	include <GL/gl.h>
#elif GLF_GRAPHICAL_API_OPENGL_ES
#ifndef __ANDROID__
#	include <GLES/egl.h>
#endif
#endif

#ifdef GLF_DEBUGGER_VERBOSE
#	define GLF_DEBUGGER_VERBOSE_PRINT(...) printf(__VA_ARGS__)
#else
#	define GLF_DEBUGGER_VERBOSE_PRINT(...)
#endif

#include <zlib.h>

namespace glf
{
namespace debugger
{
	inline uint imin(uint a, uint b) { return a < b ? a : b; }

	extern Atomic32 sInternalAllocatedSize;
	extern Atomic32 sInternalAllocations;
	stringdbg sGlfRootPath;

#if defined(WIN32) && !defined(GLF_PLATFORM_WP8)
	// get path to spawn remote debugger
// get path to spawn remote debugger
	void SpawnRemoteDebugger()
	{
		Debugger* debugger = Debugger::GetInstance();
		if(debugger == NULL)
			return;

		if(debugger->IsConnected())
		{
			debugger::CommonModule::GetInstance()->ShowDebugger();
			return;
		}

		char hostAddress[256];
		debugger->GetHostAddress(hostAddress, sizeof(hostAddress));
		ushort listeningPort = debugger->GetListeningPort();

		char szPath[256] = {0};
		if(sGlfRootPath.size() > 0)
		{
			strncpy(szPath, sGlfRootPath.c_str(), sizeof(szPath));
		}
		else
		{
			HKEY hKey;
			DWORD dwBufLen = sizeof(szPath);

			RegOpenKeyEx(HKEY_CURRENT_USER,
						 "Software\\Gameloft\\GLF",
						 0,
						 KEY_QUERY_VALUE,
						 &hKey);
			RegQueryValueEx(hKey, "Path", NULL, NULL, (LPBYTE)szPath, &dwBufLen);
			RegCloseKey(hKey);
		}

		if(strlen(szPath) > 0)
		{
			char buffer[512];
			sprintf(buffer, "%s\\tools\\debugger\\glfDebugger.exe -connect %s %d", szPath, hostAddress, listeningPort);

			STARTUPINFO si;
			PROCESS_INFORMATION pi;

			ZeroMemory(&si, sizeof(si));
			si.cb = sizeof(si);
			ZeroMemory(&pi, sizeof(pi));

			CreateProcess(NULL,   // No module name (use command line)
						  buffer, // Command line
						  NULL,   // Process handle not inheritable
						  NULL,   // Thread handle not inheritable
						  FALSE,  // Set handle inheritance to FALSE
						  0,      // No creation flags
						  NULL,   // Use parent's environment block
						  NULL,   // Use parent's starting directory 
						  &si,    // Pointer to STARTUPINFO structure
						  &pi);  // Pointer to PROCESS_INFORMATION structure
		}
	}

	typedef USHORT (WINAPI *pRTLCaptureStackBackTrace)(ULONG, ULONG, PVOID*, PULONG);
	pRTLCaptureStackBackTrace RtlCaptureStackBackTrace = 0;
	bool Symbolized = false;

	const uint		MAX_STACK_SIZE = 256;	// DONT GO OVER 63 (by combining NUM_TO_SKIP+MAX_STACK_SIZE)
	const ULONG		NUM_TO_SKIP = 3;
	void*			CallStackBuffer[MAX_STACK_SIZE+NUM_TO_SKIP];

#else

	void SpawnRemoteDebugger()
	{
	}

#endif

	void SetGlfRootPath(const char* path)
	{
		sGlfRootPath = path;
	}

	static DebuggerMutex& GetLock()
	{
		static DebuggerMutex *lock = new(Alloc(sizeof(DebuggerMutex))) DebuggerMutex(MUTEX_RECURSIVE);
		return *lock;
	}

	ScopeMutex::ScopeMutex()
	{
		GetLock().Lock();
	}

	ScopeMutex::~ScopeMutex()
	{
		GetLock().Unlock();
	}

	PacketWriter& Module::GetPacketWriter()
	{
		return mDebugger->GetPacketWriter();
	}

	Module::Module(const char* name, const char* modulePath) : mName(name), mModulePath(modulePath), mDebugger(NULL) 
	{
		
	}

	Module::~Module() 
	{
		
	}

	void Module::Send(PacketWriter& writer)
	{
		if(mDebugger->mNetSocket != NULL)
		{
			writer.Flush(this, mDebugger->mNetSocket);
		}
	}

	//-------------------
	// Packet Writer
	//-------------------

	void PacketWriter::Flush(Module* module, CNetSocket* s)
	{
		GLF_DEBUGGER_VERBOSE_PRINT("send %d bytes\n", mSize);

		uchar header[8];
		header[0] = (uchar)(mSize & 0xff);
		header[1] = (uchar)((mSize >> 8) & 0xff);
		header[2] = (uchar)((mSize >> 16) & 0xff);
		header[3] = (uchar)((mSize >> 24) & 0xff);

		header[4] = (uchar)(mType & 0xff);
		header[5] = (uchar)((mType >> 8) & 0xff);
		header[6] = (uchar)((mType >> 16) & 0xff);
		header[7] = (uchar)((mType >> 24) & 0xff);

		s->write(&header[0], sizeof(header), 1);

		uchar moduleName[8] = {0};
		GLF_ASSERT(module->GetName().size() <= 8);
		memcpy(moduleName, module->GetName().c_str(), module->GetName().size());
		s->write(&moduleName[0], sizeof(moduleName), 1);
		
		if(mSize > 0)
			s->write(&mData[0], mSize, 1);

		GLF_DEBUGGER_VERBOSE_PRINT("done\n");
	}

	//-------------------
	// Debugger
	//-------------------
	//FileSystem sFileSystemModule;
	bool sDestroyed = false;

	GLF_DEFINE_SINGLETON_PLACEMENT_NEW(Debugger)

	Debugger::Debugger() :
		mNet(NULL),
		mNetSocket(NULL),
		mPort(-1),
		mRendererType(NULL_RENDER),
		mNetMulticast(0)
	{
		
	}

	Debugger::~Debugger()
	{
		for(ModuleMap::iterator it = mModules.begin(); it != mModules.end(); ++it)
		{
			it->second->DebuggerDestroyed();
		}

		sDestroyed = true;
		Close();

		if(mNet != NULL)
			delete mNet;
		mNet = NULL;

		if(mNetMulticast != NULL)
			delete mNetMulticast;
		mNetMulticast = NULL;
	}

	bool Debugger::OnEvent(const CoreEvent& evt) {
		if(evt.mType == AET_SYSTEM)
		{
			const SystemEvent& sysEvt = static_cast<const SystemEvent&>(evt);
			if(sysEvt.mSubType == glf::SET_BECAME_ACTIVE)
			{
				InitSockets();
			}
			else if(sysEvt.mSubType == glf::SET_WILL_RESIGN_ACTIVE)
			{	
				DeinitSockets();
			}
		}
		return false;
	}
	
	void Debugger::InitSockets()
	{
		if(mNetMulticast == 0)
			mNetMulticast = new CNetInterface();
		if(mNet == 0)
		{
			mNet = new CNetInterface();

			Listen();
		}
	}
	
	void Debugger::Listen()
	{
		//if already assigned a port, try to listen only once per frame
		int numTries = mPort >= 0 ? 1 : 10;
		for(int i = 0; i < numTries; i++)
		{
			int port = mPort >= 0 ? mPort : GLF_DEBUGGER_PORT + i;
			if(mNet->listen(port))
			{
				char buffer[512] = {0};
				mNet->getHostName(buffer, 255);
				mPort = port;
#ifdef WIN32
				printf("debugger listening: %s:%d\n", buffer, mNet->getPort());
#else
				glf::Console::Print("debugger listening: %s:%d\n", buffer, mNet->getPort());
#endif
				break;
			}
		}	
	}
	
	void Debugger::DeinitSockets()
	{
		Close();
		
		mNetSocket = 0;
		if(mNet)
			delete mNet;
		mNet = 0;
		if(mNetMulticast)
			delete mNetMulticast;
		mNetMulticast = 0;
	}

	bool Debugger::Init(int rendererType)
	{
		GLF_ASSERT(mNet == NULL);

		if(!CNetInterfaceInit())
        {
            return false;
        }

		mRendererType = rendererType;

		InitSockets();

		RegisterModule( MemoryMonitor::GetInstance());
		RegisterModule( CommonModule::GetInstance());		
		RegisterModule( Console::GetInstance());
		RegisterModule( PerfCounters::GetInstance());
		RegisterModule( Macros::GetInstance());
		RegisterModule( Profiler::GetInstance());
		RegisterModule( Tweakers::GetInstance());
		//RegisterModule( FileSystem::GetInstance());
		RegisterModule( Network::GetInstance());

#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(OS_WP8)
		const char* waitString = getenv("WAIT_CONNECTION");
		if(waitString != NULL && strcmp(waitString, "true") == 0)
		{
			WaitForConnection(10);
		}
#endif

		return true;
	}

	void Debugger::Close()
	{
		GLF_DEBUGGER_VERBOSE_PRINT("Close\n");

		if(mNetSocket != NULL)
		{
			delete mNetSocket;
			mNetSocket = NULL;

			for(ModuleMap::iterator it = mModules.begin(); it != mModules.end(); ++it)
			{
				it->second->ConnectionClosed();
			}
		}
	}

	bool Debugger::WaitForConnection(uint timeOutSeconds)
	{
		int64 timeLimit = GetMilliseconds() + (timeOutSeconds * 1000);

		while(!IsConnected())
		{
			if(GetMilliseconds() >= timeLimit)
				return false;

			Update();
			
			Thread::Sleep(5);
		}
		return true;
	}

	bool Debugger::GetHostAddress(char* buffer, uint bufferLen) const
	{
		return mNet->getHostAddress(buffer, bufferLen);
	}
	
	ushort Debugger::GetListeningPort() const
	{
		return mNet->getPort();
	}

	void Debugger::CheckDebuggerMultiCast()
	{
		if(!mNetMulticast->isValid())
		{
			GLF_DEBUGGER_VERBOSE_PRINT("setupReceiveMulticast\n");
			mNetMulticast->setupReceiveMulticast("234.5.6.7", 4567);
		}

		char buffer[1000];
		if(mNetMulticast->receiveMulticast(buffer, sizeof(buffer)) > 0)
		{
			const char* sep = strstr(buffer, ":");
			if(sep != NULL)
			{
				// Parse address and port
				char address[255];
				int len = sep - buffer;
				memcpy(address, buffer, len);
				address[len] = '\0';
				
				int port = atoi(sep + 1);

#ifdef WIN32
				// prevent responding to other PCs
				if(mNetMulticast->getHostAddress(buffer, 255) && strcmp(buffer, address) != 0)
					return;
#endif

				GLF_DEBUGGER_VERBOSE_PRINT("received multicast from %s:%d\n", address, port);

				GetDeviceInfos(buffer, sizeof(buffer));
				mNetMulticast->sendDatagram(address, port, buffer, strlen(buffer));
			}
			else
			{
				GLF_DEBUGGER_VERBOSE_PRINT("received multicast\n");
			}
		}
	}

	void Debugger::GetDeviceInfos(char* buffer, uint length)
	{
		strcpy(buffer, "host=");
		mNetMulticast->getHostName(buffer + strlen(buffer), 255);
		sprintf(buffer + strlen(buffer), ":%d\n", mNet->getPort());
		//sprintf(buffer + strlen(buffer), "version=%s\n", Device->getVersion());
		sprintf(buffer + strlen(buffer), "renderer=%s\n", GetRendererName());
		sprintf(buffer + strlen(buffer), "os=%s\n", GetPlatformName());
		sprintf(buffer + strlen(buffer), "identifier=%s\n", GLF_DEBUGGER_IDENTIFIER);

		GLF_ASSERT(strlen(buffer) < length);
	}

	const char* Debugger::GetRendererName() const
	{
		switch(mRendererType)
		{
		case NULL_RENDER:		return "Null";
		case OPENGL_ES_1:		return "OpenGL ES 1";
		case OPENGL_ES_2:		return "OpenGL ES 2";
		case OPENGL_ES:			return "OpenGL ES";
		case OPENGL_FIXED:		return "OpenGL Fixed";
		case OPENGL_GLSL:		return "OpenGL GLSL";
		case OPENGL_CG:			return "OpenGL Cg";
		case OPENGL:			return "OpenGL";
		case DIRECT3D_11:		return "Direct3D 11";
		case GXM_PSP2:			return "sceGXM";
		case PLATFORM_SPECIFIC:	
#if GLF_PLATFORM_CTR
            return "OpenGL ES2 DMP / Gr";
#else
            return "Platform Specific";
#endif
		default:				return "Unknown";
		}
	}

	const char* Debugger::GetPlatformName() const
	{
#if GLF_PLATFORM_IPHONE
		return "iPhone";
#elif GLF_PLATFORM_PS3
		return "PS3";
#elif GLF_PLATFORM_WP8
		return "WP8";
#elif GLF_PLATFORM_WIN32
		return "Windows";
#elif GLF_PLATFORM_PSP2
		return "PSP2";
#elif GLF_PLATFORM_CTR
		return "CTR (3DS)";
#elif GLF_PLATFORM_ANDROID
		return "Android";
#elif defined(GLF_PLATFORM)
// Fallback to the content of GLF_PLATFORM
#   define STRINGIZE(X) DO_STRINGIZE(X)
#   define DO_STRINGIZE(X) #X
        return STRINGIZE(GLF_PLATFORM);
#else
		return "Unknown";
#endif
	}

	void Debugger::RegisterModule(Module* module)
	{
		GLF_ASSERT(module->mName.size() <= 8);
		GLF_ASSERT(mModules.find(module->mName) == mModules.end());
		mModules[module->mName] = module;
		module->mDebugger = this;
	}

	void Debugger::UnregisterModule(Module* module)
	{
        // When destructing, the lis
        if(!mModules.empty())
        {
		    GLF_ASSERT(mModules.find(module->mName) != mModules.end());
		    mModules.erase(mModules.find(module->mName));
        }
	}

	static const float DEFAULT_TIMEOUT = 5.0f; // 5 sec

	void Debugger::Update()
	{
		if (mNet == NULL)
		{
			return;
		}
#ifdef _PS3
		 cellSysutilCheckCallback();
#endif

		if(mNetSocket == NULL)
		{
			CheckDebuggerMultiCast();
			mNetSocket = mNet->accept();

			if(mNetSocket != NULL)
			{
				//std::cout<<"test"<<endl;
				//Console::Print("test");
				mNetSocket->setNonBlock(false);
				mNetMulticast->close();
			}
			else
			{
				if(!mNet->isValid())
					Listen();
				return;
			}
		}

		uchar stackBuffer[256];

		if(!mNetSocket->isOpen())
		{
			Close();
			return;
		}

		while(mNetSocket->isReadable())
		{
			uchar header[8];

			uint count = 0;
			count = mNetSocket->read(&header[0], 4, DEFAULT_TIMEOUT);
			if(count == 0 || count != 4 || !mNetSocket->isOpen())
			{
				Close();
				return;
			}
			GLF_ASSERT(count == 4);
			uint len = (header[0]) | (header[1] << 8) | (header[2] << 16) | (header[3] << 24);

			count = mNetSocket->read(&header[4], 4, DEFAULT_TIMEOUT);
			if(!mNetSocket->isOpen() || count != 4)
			{
				Close();
				return;
			}
			GLF_ASSERT(count == 4);
			uint type = (header[4]) | (header[5] << 8) | (header[6] << 16) | (header[7] << 24);

			char moduleId[9] = {0};
			count = mNetSocket->read(moduleId, 8, DEFAULT_TIMEOUT);
			if(!mNetSocket->isOpen() || count != 8)
			{
				Close();
				return;
			}
			GLF_ASSERT(count == 8);
			stringdbg moduleName = (const char*)moduleId;
			
			GLF_DEBUGGER_VERBOSE_PRINT("receive type=%d len=%d module=%s\n", type, len, moduleName.c_str());

			uchar* data = len > 0 ? stackBuffer : NULL;
			if(len > 0)
			{
				if(len > sizeof(stackBuffer))
					data = new uchar[len];
				
				GLF_ASSERT(data != NULL);
				count = mNetSocket->read(data, len, DEFAULT_TIMEOUT);
				if(count != len || !mNetSocket->isOpen())
				{
					if(data != NULL && data != stackBuffer)
						delete[] data;

					Close();
					return;
				}
				GLF_ASSERT(count == len);
			}

			PacketReader in(data, len);
			ModuleMap::const_iterator it = mModules.find(moduleName);
			if(it != mModules.end())
			{
				it->second->Parse(type, in);
			}

			if(data != NULL && data != stackBuffer)
				delete[] data;

			GLF_DEBUGGER_VERBOSE_PRINT("packet parsed\n");
		}
	}

	void Debugger::UpdateFrame()
	{
		for(ModuleMap::iterator it = mModules.begin(); it != mModules.end(); ++it)
		{
			it->second->UpdateFrame();
		}

		PerfCounters::UpdateValue("AllocSize.Debugger", sInternalAllocatedSize);
		PerfCounters::UpdateValue("AllocCount.Debugger", sInternalAllocations);

		Update();
	}

	CommonModule::CommonModule() :
		 Module("COMMON")
	{
#if defined(WIN32) && !defined(GLF_PLATFORM_WP8)
		HMODULE hMod = ::GetModuleHandle("kernel32");
		RtlCaptureStackBackTrace = (pRTLCaptureStackBackTrace)::GetProcAddress(hMod, "RtlCaptureStackBackTrace");

		SymSetOptions(  SYMOPT_UNDNAME  | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
		HANDLE hProcess = GetCurrentProcess();

		Symbolized = SymInitialize(hProcess, NULL, TRUE) != 0;
		if(!Symbolized)
			glf::Console::Print("Failed to symbolize process");
#endif
	}

	GLF_DEFINE_SINGLETON_WITH_DEP(CommonModule, Debugger)

	CommonModule::~CommonModule()
	{
        if( glf::debugger::Debugger::GetInstance() )
        {
		    glf::debugger::Debugger::GetInstance()->UnregisterModule( this );
        }
	}

	void CommonModule::UpdateFrame()
	{
	}

	void CommonModule::Parse(int type, PacketReader& in)
	{
		switch(type)
		{
			case MESSAGE_REQUEST_CALLSTACK_SYMBOLS:
			{
				stringdbg destModuleId = in.ReadString();
				stringdbg tag = in.ReadString();
				uint depth = (uint)in.ReadIntLE();
				GLF_ASSERT(depth < 64);
				
				unsigned long callStack[64];
				for(uint i = 0; i < depth; i++)
					callStack[i] = (unsigned long)in.ReadIntLE();

				SendCallStackSymbols(destModuleId, tag, depth, callStack);
				break;
			}

			case MESSAGE_REQUEST_DEVICE_INFOS:
			{
				char buffer[1000];
				GetDebugger()->GetDeviceInfos(buffer, sizeof(buffer));

				PacketWriter& pw = GetPacketWriter();
				pw.Init(MESSAGE_DEVICE_INFOS);
				pw.Write(buffer);
				Send(pw);
				break;
			}

			case MESSAGE_REQUEST_MODULE_LIST:
			{
				PacketWriter& pw = GetPacketWriter();
				pw.Init(MESSAGE_MODULE_LIST);
				int count = GetDebugger()->mModules.size();
				pw.Write(count);
				for(Debugger::ModuleMap::const_iterator it = GetDebugger()->mModules.begin(); it != GetDebugger()->mModules.end(); ++it)
				{
					pw.Write(it->second->GetName().c_str());
					pw.Write(it->second->GetModulePath().c_str());
				}
				Send(pw);
				break;
			}

			case MESSAGE_NOTIFY_DEBUGGER_READY:
			{
				// Modules are ready to communicate
				for(Debugger::ModuleMap::iterator it = GetDebugger()->mModules.begin(); it != GetDebugger()->mModules.end(); ++it)
				{
					it->second->ConnectionOpened();
				}
				break;
			}

			default:
				;
		}
	}

#if defined(WIN32) && !defined(GLF_PLATFORM_WP8)
	uint CommonModule::GetCallStack(unsigned long* callStack, uint size, unsigned long* hash)
	{
		ULONG numToCapture = 0;
		if(RtlCaptureStackBackTrace)
		{
			numToCapture = imin(size, MAX_STACK_SIZE);
			numToCapture = RtlCaptureStackBackTrace(NUM_TO_SKIP+1, numToCapture+NUM_TO_SKIP, (void**)&CallStackBuffer, hash);
			
			if(numToCapture <= NUM_TO_SKIP)
				numToCapture = 0;
			else
				numToCapture -= NUM_TO_SKIP;
		}

		::memset(callStack, 0, size * sizeof(void*));	//clear it

		if(numToCapture > 0)
		{
			::memcpy(callStack, CallStackBuffer, numToCapture*sizeof(void*));
		}
		return numToCapture;
	}

	bool CommonModule::ResolveFunctionSymbol(unsigned long address, SymbolInfo& symbolInfo)
	{
		DWORD  dwAddress = (DWORD) address;
		DWORD64  dwDisplacement;
		HANDLE hProcess = GetCurrentProcess();
		ULONG64 buffer[(sizeof(SYMBOL_INFO) +
		MAX_SYM_NAME * sizeof(TCHAR) +
		sizeof(ULONG64) - 1) /
		sizeof(ULONG64)];
		PSYMBOL_INFO pSymbol = (PSYMBOL_INFO) buffer;

		pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
		pSymbol->MaxNameLen = MAX_SYM_NAME;        

		if(SymFromAddr(hProcess, dwAddress, &dwDisplacement, pSymbol))
		{	  
			symbolInfo.FuncName = pSymbol->Name;
			IMAGEHLP_LINE64 line;
			line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
			DWORD dwDisp;
			if (SymGetLineFromAddr64(hProcess, dwAddress, &dwDisp, &line))
			{		    
				symbolInfo.FileName = line.FileName;
				symbolInfo.Line = line.LineNumber;
			}
			else
			{
				symbolInfo.FileName = "error";
				symbolInfo.Line = 666;
			}

			return true;
		}
		else
		{
			symbolInfo.FuncName = "error";
		}

		return false;
	}
#endif

	void CommonModule::SendCallStackSymbols(const stringdbg& destModuleId, const stringdbg& tag, uint depth, unsigned long* callStack)
	{
#if defined(WIN32) && !defined(GLF_PLATFORM_WP8)
		ScopeMutex mutex;
		PacketWriter& pw = GetPacketWriter();
		pw.Init(MESSAGE_CALLSTACK_SYMBOLS);

		// resolve symbols
		static char tmp[2048];

#ifdef UNICODE
		OutputDebugString(L"call stack:\n");
#else
		OutputDebugString("call stack:\n");
#endif

		pw.Write(destModuleId.c_str());
		pw.Write(tag.c_str());
		pw.Write(depth);
		for(uint i = 0; i < depth; i++)
		{
			unsigned long address = callStack[i];
			SymbolInfo symbolInfo;
			ResolveFunctionSymbol(address, symbolInfo);

			sprintf(tmp, "%s(%d): %s\n", symbolInfo.FileName.c_str(), symbolInfo.Line, symbolInfo.FuncName.c_str());
#ifdef UNICODE
			std::string strTmp(tmp);
			std::wstring wTmp(strTmp.begin(), strTmp.end());
			OutputDebugString(wTmp.c_str());
#else			
			OutputDebugString(tmp);
#endif
			GLF_ASSERT(strlen(tmp) < sizeof(tmp));
			
			// symbol map
			pw.Write(symbolInfo.FuncName.c_str());
			pw.Write(symbolInfo.FileName.c_str());
			pw.Write(symbolInfo.Line);
		}

		Send(pw);
#endif
	}

	void CommonModule::SendFrameBuffer(bool depthBuffer)
	{
		ScopeMutex mutex;
		uint width = 0;
		uint height = 0;
		CaptureScreenBuffer(width, height, depthBuffer);
		uint size = width * height * 4;

		if(depthBuffer)
		{
			float zNear = 1000000.0f;
			float zFar = -10000000.0f;
			
			PacketWriter& pw = GetPacketWriter();
			pw.Init(MESSAGE_DEPTH_BUFFER);
			pw.Write(width);
			pw.Write(height);
			pw.Write(4);
			pw.Write(zNear);
			pw.Write(zFar);
			pw.Write(&mFrameBuffer[0], size);
			Send(pw);
		}
		else
		{
			PacketWriter& pw = GetPacketWriter();
			pw.Init(MESSAGE_COLOR_BUFFER);
			pw.Write(width);
			pw.Write(height);
			pw.Write(4);
			pw.Write(&mFrameBuffer[0], size);
			Send(pw);
		}
	}

	void CommonModule::CaptureScreenBuffer(uint& width, uint& height, bool depth)
	{
#if 0 //defined(GLF_GRAPHICAL_API_OPENGL) || defined(GLF_GRAPHICAL_API_OPENGL_ES)
		int viewport[4];
		glGetIntegerv(GL_VIEWPORT, viewport);
		glGetError();

		width = (uint)viewport[2];
		height = (uint)viewport[3];
		uint size = width * height * 4;
		if(mFrameBuffer.size() < size)
			mFrameBuffer.resize(size);

		if(depth)
			glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, &mFrameBuffer[0]);
		else
			glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &mFrameBuffer[0]);
		glGetError();

		// opengl images are horizontally flipped, so we have to fix that here.
		uchar* pPixels = &mFrameBuffer[0];
		const uint pitch = width * 4;
		uchar* p2 = pPixels + (height - 1) * pitch;
		std::vector<uchar> tmpBuffer;
		tmpBuffer.resize(pitch);

		for (uint i=0; i < height; i += 2)
		{
			memcpy(&tmpBuffer[0], pPixels, pitch);
			memcpy(pPixels, p2, pitch);
			memcpy(p2, &tmpBuffer[0], pitch);
			pPixels += pitch;
			p2 -= pitch;
		}
#endif
	}

	void CommonModule::HandleKeyEvent(int keyCode)
	{
		PacketWriter& pw = GetPacketWriter();
		pw.Init(MESSAGE_HANDLE_KEY_EVENT);
		pw.Write((uint)keyCode);
		Send(pw);
	}

	void CommonModule::GenerateReport(const ReportInfo& info)
	{
		PacketWriter& pw = GetPacketWriter();
		pw.Init(MESSAGE_GENERATE_REPORT);
		pw.Write(info.mName.c_str());
		Send(pw);
	}

	void CommonModule::ShowDebugger()
	{
		PacketWriter& pw = GetPacketWriter();
		pw.Init(MESSAGE_SHOW_DEBUGGER);
		Send(pw);
	}

}; // end namespace debugger
}; // end namespace glf

#else

namespace glf {
	namespace debugger {
		void* Alloc(size_t cnt)
		{
			return malloc(cnt);
		}

		void Free(void* ptr)
		{
			free(ptr);
		}
	}
}
#endif // GLF_ENABLE_DEBUGGER
